package com.itaming.lycheeframework.support.utils;

import com.itaming.lycheeframework.support.cipher.CipherAlgorithm;
import com.itaming.lycheeframework.support.cipher.CipherConstant;
import com.itaming.lycheeframework.support.cipher.Encryptor;
import com.itaming.lycheeframework.support.cipher.EncryptorFactory;
import com.itaming.lycheeframework.support.cipher.asymmetric.AsymmetricEncryptorOptions;
import com.itaming.lycheeframework.support.cipher.gm.Sm2KeyPair;
import com.itaming.lycheeframework.support.cipher.gm.Sm2SpiProvider;
import com.itaming.lycheeframework.support.cipher.symmetric.SymmetricEncryptorOptions;
import lombok.experimental.UtilityClass;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.util.Assert;

import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.function.Function;

/**
 * Cipher工具类
 *
 * @author A.Ming
 */
@UtilityClass
public class CipherUtil {

    static {
        // 实例化 Bouncy Castle 加密提供程序
        BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
        // 添加改造后的SM2加密算法
        bouncyCastleProvider.replace("Cipher." + CipherConstant.ALGORITHM_SM2, Sm2SpiProvider.C1C3C2.class.getName());
        bouncyCastleProvider.addAlgorithm("Alg.Alias.Cipher." + CipherConstant.ALGORITHM_SM2_C1C3C2, CipherConstant.ALGORITHM_SM2);
        bouncyCastleProvider.addAlgorithm("Cipher." + CipherConstant.ALGORITHM_SM2_C1C2C3, Sm2SpiProvider.C1C2C3.class.getName());
        // 添加 Bouncy Castle 加密提供程序，扩展 "PKCS7Padding"、"SM4" 等
        Security.addProvider(bouncyCastleProvider);
    }

    /**
     * 生成密钥
     *
     * @param bitLength 长度
     * @return 密钥
     */
    public static String generateSecretKey(int bitLength) {
        return StringUtil.random(bitLength / 8, true, true);
    }

    /**
     * 生成初始化向量
     *
     * @param bitLength 长度
     * @return 初始化向量
     */
    public static String generateIv(int bitLength) {
        return StringUtil.random(bitLength / 8, true, true);
    }

    /**
     * 生成RSA密钥对
     *
     * @param bitLength 长度
     * @return 密钥对
     */
    public static KeyPair generateRsaKeyPair(int bitLength) {
        KeyPairGenerator instance;

        try {
            instance = KeyPairGenerator.getInstance(CipherConstant.ALGORITHM_RSA);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("Could not find Cipher with algorithm \"" + CipherConstant.ALGORITHM_RSA + "\"", e);
        }

        instance.initialize(bitLength);

        return instance.generateKeyPair();
    }

    /**
     * 获取SM2密钥对
     *
     * @return SM2密钥对
     */
    public static Sm2KeyPair generateSm2KeyPair() {
        KeyPairGenerator instance;
        try {
            instance = KeyPairGenerator.getInstance(CipherConstant.ALGORITHM_EC, BouncyCastleProvider.PROVIDER_NAME);
            instance.initialize(new ECGenParameterSpec(CipherConstant.SM2_CURVE_NAME), new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("Could not find Cipher with algorithm \"" + CipherConstant.ALGORITHM_EC + "\"", e);
        } catch (InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException("Invalid sm2 curve parameter", e);
        } catch (NoSuchProviderException e) {
            throw new IllegalArgumentException("Could not find Cipher provider \"" + BouncyCastleProvider.PROVIDER_NAME + "\"", e);
        }

        KeyPair keyPair = instance.generateKeyPair();

        return Sm2KeyPair.of((BCECPublicKey) keyPair.getPublic(), (BCECPrivateKey) keyPair.getPrivate());
    }

    /**
     * AES-128加密
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptAes128(byte[] data, String secretKey, String iv) {
        return encrypt(CipherAlgorithm.AES_128_CBC, data, secretKey, iv);
    }

    /**
     * AES-128加密
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptAes128(String str, String secretKey, String iv) {
        return encryptAes128(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-128加密，转为字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptAes128(byte[] data, String secretKey, String iv, Function<byte[], String> converter) {
        checkConverter(converter);
        return converter.apply(encryptAes128(data, secretKey, iv));
    }

    /**
     * AES-128加密，转为字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptAes128(String str, String secretKey, String iv, Function<byte[], String> converter) {
        return encryptAes128(StringUtil.getBytes(str), secretKey, iv, converter);
    }

    /**
     * AES-128加密，转为Hex字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes128ToHex(byte[] data, String secretKey, String iv) {
        return encryptAes128(data, secretKey, iv, HexUtil::encodeToString);
    }

    /**
     * AES-128加密，转为Hex字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes128ToHex(String str, String secretKey, String iv) {
        return encryptAes128ToHex(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-128加密，转为Base64字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes128ToBase64(byte[] data, String secretKey, String iv) {
        return encryptAes128(data, secretKey, iv, Base64Util::encodeToString);
    }

    /**
     * AES-128加密，转为Base64字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes128ToBase64(String str, String secretKey, String iv) {
        return encryptAes128ToBase64(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-192加密
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptAes192(byte[] data, String secretKey, String iv) {
        return encrypt(CipherAlgorithm.AES_192_CBC, data, secretKey, iv);
    }

    /**
     * AES-192加密
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptAes192(String str, String secretKey, String iv) {
        return encryptAes192(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-192加密，转为字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptAes192(byte[] data, String secretKey, String iv, Function<byte[], String> converter) {
        checkConverter(converter);
        return converter.apply(encryptAes192(data, secretKey, iv));
    }

    /**
     * AES-192加密，转为字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptAes192(String str, String secretKey, String iv, Function<byte[], String> converter) {
        return encryptAes192(StringUtil.getBytes(str), secretKey, iv, converter);
    }

    /**
     * AES-192加密，转为Hex字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes192ToHex(byte[] data, String secretKey, String iv) {
        return encryptAes192(data, secretKey, iv, HexUtil::encodeToString);
    }

    /**
     * AES-192加密，转为Hex字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes192ToHex(String str, String secretKey, String iv) {
        return encryptAes192ToHex(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-192加密，转为Base64字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes192ToBase64(byte[] data, String secretKey, String iv) {
        return encryptAes192(data, secretKey, iv, Base64Util::encodeToString);
    }

    /**
     * AES-192加密，转为Base64字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes192ToBase64(String str, String secretKey, String iv) {
        return encryptAes192ToBase64(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-256加密
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptAes256(byte[] data, String secretKey, String iv) {
        return encrypt(CipherAlgorithm.AES_256_CBC, data, secretKey, iv);
    }

    /**
     * AES-256加密
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptAes256(String str, String secretKey, String iv) {
        return encryptAes256(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-256加密，转为字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptAes256(byte[] data, String secretKey, String iv, Function<byte[], String> converter) {
        checkConverter(converter);
        return converter.apply(encryptAes256(data, secretKey, iv));
    }

    /**
     * AES-256加密，转为字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptAes256(String str, String secretKey, String iv, Function<byte[], String> converter) {
        return encryptAes256(StringUtil.getBytes(str), secretKey, iv, converter);
    }

    /**
     * AES-256加密，转为Hex字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes256ToHex(byte[] data, String secretKey, String iv) {
        return encryptAes256(data, secretKey, iv, HexUtil::encodeToString);
    }

    /**
     * AES-256加密，转为Hex字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes256ToHex(String str, String secretKey, String iv) {
        return encryptAes256ToHex(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * AES-256加密，转为Base64字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes256ToBase64(byte[] data, String secretKey, String iv) {
        return encryptAes256(data, secretKey, iv, Base64Util::encodeToString);
    }

    /**
     * AES-256加密，转为Base64字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptAes256ToBase64(String str, String secretKey, String iv) {
        return encryptAes256ToBase64(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * DES加密
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptDes(byte[] data, String secretKey, String iv) {
        return encrypt(CipherAlgorithm.DES_CBC, data, secretKey, iv);
    }

    /**
     * DES加密
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptDes(String str, String secretKey, String iv) {
        return encryptDes(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * DES加密，转为字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptDes(byte[] data, String secretKey, String iv, Function<byte[], String> converter) {
        checkConverter(converter);
        return converter.apply(encryptDes(data, secretKey, iv));
    }

    /**
     * DES加密，转为字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptDes(String str, String secretKey, String iv, Function<byte[], String> converter) {
        return encryptDes(StringUtil.getBytes(str), secretKey, iv, converter);
    }

    /**
     * DES加密，转为Hex字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptDesToHex(byte[] data, String secretKey, String iv) {
        return encryptDes(data, secretKey, iv, HexUtil::encodeToString);
    }

    /**
     * DES加密，转为Hex字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptDesToHex(String str, String secretKey, String iv) {
        return encryptDesToHex(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * DES加密，转为Base64字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptDesToBase64(byte[] data, String secretKey, String iv) {
        return encryptDes(data, secretKey, iv, Base64Util::encodeToString);
    }

    /**
     * DES加密，转为Base64字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptDesToBase64(String str, String secretKey, String iv) {
        return encryptDesToBase64(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * SM4加密
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptSm4(byte[] data, String secretKey, String iv) {
        return encrypt(CipherAlgorithm.SM4_CBC, data, secretKey, iv);
    }

    /**
     * SM4加密
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的数据
     */
    public static byte[] encryptSm4(String str, String secretKey, String iv) {
        return encryptSm4(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * SM4加密，转为字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptSm4(byte[] data, String secretKey, String iv, Function<byte[], String> converter) {
        checkConverter(converter);
        return converter.apply(encryptSm4(data, secretKey, iv));
    }

    /**
     * SM4加密，转为字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptSm4(String str, String secretKey, String iv, Function<byte[], String> converter) {
        return encryptSm4(StringUtil.getBytes(str), secretKey, iv, converter);
    }

    /**
     * SM4加密，转为Hex字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptSm4ToHex(byte[] data, String secretKey, String iv) {
        return encryptSm4(data, secretKey, iv, HexUtil::encodeToString);
    }

    /**
     * SM4加密，转为Hex字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptSm4ToHex(String str, String secretKey, String iv) {
        return encryptSm4ToHex(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * SM4加密，转为Base64字符串
     *
     * @param data      待加密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptSm4ToBase64(byte[] data, String secretKey, String iv) {
        return encryptSm4(data, secretKey, iv, Base64Util::encodeToString);
    }

    /**
     * SM4加密，转为Base64字符串
     *
     * @param str       待加密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 加密后的字符串
     */
    public static String encryptSm4ToBase64(String str, String secretKey, String iv) {
        return encryptSm4ToBase64(StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * RSA加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后的数据
     */
    public static byte[] encryptRsa(byte[] data, byte[] publicKey) {
        return encrypt(CipherAlgorithm.RSA, data, publicKey);
    }

    /**
     * RSA加密
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @return 加密后的数据
     */
    public static byte[] encryptRsa(String str, byte[] publicKey) {
        return encryptRsa(StringUtil.getBytes(str), publicKey);
    }

    /**
     * RSA加密，转为字符串
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptRsa(byte[] data, byte[] publicKey, Function<byte[], String> converter) {
        checkConverter(converter);
        return converter.apply(encryptRsa(data, publicKey));
    }

    /**
     * RSA加密，转为字符串
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptRsa(String str, byte[] publicKey, Function<byte[], String> converter) {
        return encryptRsa(StringUtil.getBytes(str), publicKey, converter);
    }

    /**
     * RSA加密，转为Hex字符串
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptRsaToHex(byte[] data, byte[] publicKey) {
        return encryptRsa(data, publicKey, HexUtil::encodeToString);
    }

    /**
     * RSA加密，转为Hex字符串
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptRsaToHex(String str, byte[] publicKey) {
        return encryptRsaToHex(StringUtil.getBytes(str), publicKey);
    }

    /**
     * RSA加密，转为Base64字符串
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptRsaToBase64(byte[] data, byte[] publicKey) {
        return encryptRsa(data, publicKey, Base64Util::encodeToString);
    }

    /**
     * RSA加密，转为Base64字符串
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptRsaToBase64(String str, byte[] publicKey) {
        return encryptRsaToBase64(StringUtil.getBytes(str), publicKey);
    }

    /**
     * SM2加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后的数据
     */
    public static byte[] encryptSm2(byte[] data, byte[] publicKey) {
        return encrypt(CipherAlgorithm.SM2, data, publicKey);
    }

    /**
     * SM2加密
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @return 加密后的数据
     */
    public static byte[] encryptSm2(String str, byte[] publicKey) {
        return encryptSm2(StringUtil.getBytes(str), publicKey);
    }

    /**
     * SM2加密，转为字符串
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptSm2(byte[] data, byte[] publicKey, Function<byte[], String> converter) {
        checkConverter(converter);
        return converter.apply(encryptSm2(data, publicKey));
    }

    /**
     * SM2加密，转为字符串
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @param converter 转换函数
     * @return 加密后的字符串
     */
    public static String encryptSm2(String str, byte[] publicKey, Function<byte[], String> converter) {
        return encryptSm2(StringUtil.getBytes(str), publicKey, converter);
    }

    /**
     * SM2加密，转为Hex字符串
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptSm2ToHex(byte[] data, byte[] publicKey) {
        return encryptSm2(data, publicKey, HexUtil::encodeToString);
    }

    /**
     * SM2加密，转为Hex字符串
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptSm2ToHex(String str, byte[] publicKey) {
        return encryptSm2ToHex(StringUtil.getBytes(str), publicKey);
    }

    /**
     * SM2加密，转为Base64字符串
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptSm2ToBase64(byte[] data, byte[] publicKey) {
        return encryptSm2(data, publicKey, Base64Util::encodeToString);
    }

    /**
     * SM2加密，转为Base64字符串
     *
     * @param str       待加密字符串
     * @param publicKey 公钥
     * @return 加密后的字符串
     */
    public static String encryptSm2ToBase64(String str, byte[] publicKey) {
        return encryptSm2ToBase64(StringUtil.getBytes(str), publicKey);
    }

    /**
     * AES-128解密
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes128(byte[] data, String secretKey, String iv) {
        return decrypt(CipherAlgorithm.AES_128_CBC, data, secretKey, iv);
    }

    /**
     * AES-128解密，转为字符串
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes128ToString(byte[] data, String secretKey, String iv) {
        return StringUtil.newString(decryptAes128(data, secretKey, iv));
    }

    /**
     * AES-128解密
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的数据
     */
    public static byte[] decryptAes128(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        checkConverter(converter);
        return decryptAes128(converter.apply(str), secretKey, iv);
    }

    /**
     * AES-128解密，转为字符串
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的字符串
     */
    public static String decryptAes128ToString(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        return StringUtil.newString(decryptAes128(str, secretKey, iv, converter));
    }

    /**
     * AES-128解密
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes128FromHex(String hexStr, String secretKey, String iv) {
        return decryptAes128(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * AES-128解密，转为字符串
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes128FromHexToString(String hexStr, String secretKey, String iv) {
        return decryptAes128ToString(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * AES-128解密
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes128FromBase64(String base64Str, String secretKey, String iv) {
        return decryptAes128(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * AES-128解密，转为字符串
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes128FromBase64ToString(String base64Str, String secretKey, String iv) {
        return decryptAes128ToString(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * AES-192解密
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes192(byte[] data, String secretKey, String iv) {
        return decrypt(CipherAlgorithm.AES_192_CBC, data, secretKey, iv);
    }

    /**
     * AES-192解密，转为字符串
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes192ToString(byte[] data, String secretKey, String iv) {
        return StringUtil.newString(decryptAes192(data, secretKey, iv));
    }

    /**
     * AES-192解密
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的数据
     */
    public static byte[] decryptAes192(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        checkConverter(converter);
        return decryptAes192(converter.apply(str), secretKey, iv);
    }

    /**
     * AES-192解密，转为字符串
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的字符串
     */
    public static String decryptAes192ToString(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        return StringUtil.newString(decryptAes192(str, secretKey, iv, converter));
    }

    /**
     * AES-192解密
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes192FromHex(String hexStr, String secretKey, String iv) {
        return decryptAes192(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * AES-192解密
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes192FromHexToString(String hexStr, String secretKey, String iv) {
        return decryptAes192ToString(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * AES-192解密
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes192FromBase64(String base64Str, String secretKey, String iv) {
        return decryptAes192(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * AES-192解密，转为字符串
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes192FromBase64ToString(String base64Str, String secretKey, String iv) {
        return decryptAes192ToString(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * AES-256解密
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes256(byte[] data, String secretKey, String iv) {
        return decrypt(CipherAlgorithm.AES_256_CBC, data, secretKey, iv);
    }

    /**
     * AES-256解密，转为字符串
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes256ToString(byte[] data, String secretKey, String iv) {
        return StringUtil.newString(decryptAes256(data, secretKey, iv));
    }

    /**
     * AES-256解密
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的数据
     */
    public static byte[] decryptAes256(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        checkConverter(converter);
        return decryptAes256(converter.apply(str), secretKey, iv);
    }

    /**
     * AES-256解密，转为字符串
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的字符串
     */
    public static String decryptAes256ToString(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        return StringUtil.newString(decryptAes256(str, secretKey, iv, converter));
    }

    /**
     * AES-256解密
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes256FromHex(String hexStr, String secretKey, String iv) {
        return decryptAes256(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * AES-256解密，转为字符串
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes256FromHexToString(String hexStr, String secretKey, String iv) {
        return decryptAes256ToString(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * AES-256解密
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptAes256FromBase64(String base64Str, String secretKey, String iv) {
        return decryptAes256(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * AES-256解密，转为字符串
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptAes256FromBase64ToString(String base64Str, String secretKey, String iv) {
        return decryptAes256ToString(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * SM4解密
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptSm4(byte[] data, String secretKey, String iv) {
        return decrypt(CipherAlgorithm.SM4_CBC, data, secretKey, iv);
    }

    /**
     * SM4解密，转为字符串
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptSm4ToString(byte[] data, String secretKey, String iv) {
        return StringUtil.newString(decryptSm4(data, secretKey, iv));
    }

    /**
     * SM4解密
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的数据
     */
    public static byte[] decryptSm4(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        checkConverter(converter);
        return decryptSm4(converter.apply(str), secretKey, iv);
    }

    /**
     * SM4解密，转为字符串
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的字符串
     */
    public static String decryptSm4ToString(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        return StringUtil.newString(decryptSm4(str, secretKey, iv, converter));
    }

    /**
     * SM4解密
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptSm4FromHex(String hexStr, String secretKey, String iv) {
        return decryptSm4(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * SM4解密，转为字符串
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptSm4FromHexToString(String hexStr, String secretKey, String iv) {
        return decryptSm4ToString(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * SM4解密
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptSm4FromBase64(String base64Str, String secretKey, String iv) {
        return decryptSm4(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * SM4解密，转为字符串
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptSm4FromBase64ToString(String base64Str, String secretKey, String iv) {
        return decryptSm4ToString(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * DES解密
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptDes(byte[] data, String secretKey, String iv) {
        return decrypt(CipherAlgorithm.DES_CBC, data, secretKey, iv);
    }

    /**
     * DES解密，转为字符串
     *
     * @param data      待解密数据
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptDesToString(byte[] data, String secretKey, String iv) {
        return StringUtil.newString(decryptDes(data, secretKey, iv));
    }

    /**
     * DES解密
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的数据
     */
    public static byte[] decryptDes(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        checkConverter(converter);
        return decryptDes(converter.apply(str), secretKey, iv);
    }

    /**
     * DES解密，转为字符串
     *
     * @param str       待解密字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @param converter 转换函数
     * @return 解密后的字符串
     */
    public static String decryptDesToString(String str, String secretKey, String iv, Function<String, byte[]> converter) {
        return StringUtil.newString(decryptDes(str, secretKey, iv, converter));
    }

    /**
     * DES解密
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptDesFromHex(String hexStr, String secretKey, String iv) {
        return decryptDes(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * DES解密，转为字符串
     *
     * @param hexStr    待解密hex字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptDesFromHexToString(String hexStr, String secretKey, String iv) {
        return decryptDesToString(hexStr, secretKey, iv, HexUtil::decode);
    }

    /**
     * DES解密
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的数据
     */
    public static byte[] decryptDesFromBase64(String base64Str, String secretKey, String iv) {
        return decryptDes(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * DES解密，转为字符串
     *
     * @param base64Str 待解密base64字符串
     * @param secretKey 密钥
     * @param iv        初始化向量
     * @return 解密后的字符串
     */
    public static String decryptDesFromBase64ToString(String base64Str, String secretKey, String iv) {
        return decryptDesToString(base64Str, secretKey, iv, Base64Util::decode);
    }

    /**
     * RSA解密
     *
     * @param data       待解密数据
     * @param privateKey 私钥
     * @return 解密后的数据
     */
    public static byte[] decryptRsa(byte[] data, byte[] privateKey) {
        return decrypt(CipherAlgorithm.RSA, data, privateKey);
    }

    /**
     * RSA解密，转为字符串
     *
     * @param data       待解密数据
     * @param privateKey 私钥
     * @return 解密后的字符串
     */
    public static String decryptRsaToString(byte[] data, byte[] privateKey) {
        return StringUtil.newString(decryptRsa(data, privateKey));
    }

    /**
     * RSA解密
     *
     * @param str        待解密字符串
     * @param privateKey 私钥
     * @param converter  转换函数
     * @return 解密后的数据
     */
    public static byte[] decryptRsa(String str, byte[] privateKey, Function<String, byte[]> converter) {
        checkConverter(converter);
        return decryptRsa(converter.apply(str), privateKey);
    }

    /**
     * RSA解密，转为字符串
     *
     * @param str        待解密字符串
     * @param privateKey 私钥
     * @param converter  转换函数
     * @return 解密后的字符串
     */
    public static String decryptRsaToString(String str, byte[] privateKey, Function<String, byte[]> converter) {
        return StringUtil.newString(decryptRsa(str, privateKey, converter));
    }

    /**
     * RSA解密
     *
     * @param hexStr     待解密hex字符串
     * @param privateKey 密钥
     * @return 解密后的数据
     */
    public static byte[] decryptRsaFromHex(String hexStr, byte[] privateKey) {
        return decryptRsa(hexStr, privateKey, HexUtil::decode);
    }

    /**
     * RSA解密，转为字符串
     *
     * @param hexStr     待解密hex字符串
     * @param privateKey 密钥
     * @return 解密后的字符串
     */
    public static String decryptRsaFromHexToString(String hexStr, byte[] privateKey) {
        return decryptRsaToString(hexStr, privateKey, HexUtil::decode);
    }

    /**
     * RSA解密
     *
     * @param base64Str  待解密base64字符串
     * @param privateKey 密钥
     * @return 解密后的数据
     */
    public static byte[] decryptRsaFromBase64(String base64Str, byte[] privateKey) {
        return decryptRsa(base64Str, privateKey, Base64Util::decode);
    }

    /**
     * RSA解密，转为字符串
     *
     * @param base64Str  待解密base64字符串
     * @param privateKey 密钥
     * @return 解密后的字符串
     */
    public static String decryptRsaFromBase64ToString(String base64Str, byte[] privateKey) {
        return decryptRsaToString(base64Str, privateKey, Base64Util::decode);
    }

    /**
     * SM2解密
     *
     * @param data       待解密数据
     * @param privateKey 私钥
     * @return 解密后的数据
     */
    public static byte[] decryptSm2(byte[] data, byte[] privateKey) {
        return decrypt(CipherAlgorithm.SM2, data, privateKey);
    }

    /**
     * SM2解密，转为字符串
     *
     * @param data       待解密数据
     * @param privateKey 私钥
     * @return 解密后的字符串
     */
    public static String decryptSm2ToString(byte[] data, byte[] privateKey) {
        return StringUtil.newString(decryptSm2(data, privateKey));
    }

    /**
     * SM2解密
     *
     * @param str        待解密字符串
     * @param privateKey 私钥
     * @param converter  转换函数
     * @return 解密后的数据
     */
    public static byte[] decryptSm2(String str, byte[] privateKey, Function<String, byte[]> converter) {
        checkConverter(converter);
        return decryptSm2(converter.apply(str), privateKey);
    }

    /**
     * SM2解密，转为字符串
     *
     * @param str        待解密字符串
     * @param privateKey 私钥
     * @param converter  转换函数
     * @return 解密后的字符串
     */
    public static String decryptSm2ToString(String str, byte[] privateKey, Function<String, byte[]> converter) {
        return StringUtil.newString(decryptSm2(str, privateKey, converter));
    }

    /**
     * SM2解密
     *
     * @param hexStr     待解密hex字符串
     * @param privateKey 密钥
     * @return 解密后的数据
     */
    public static byte[] decryptSm2FromHex(String hexStr, byte[] privateKey) {
        return decryptSm2(hexStr, privateKey, HexUtil::decode);
    }

    /**
     * SM2解密，转为字符串
     *
     * @param hexStr     待解密hex字符串
     * @param privateKey 密钥
     * @return 解密后的字符串
     */
    public static String decryptSm2FromHexToString(String hexStr, byte[] privateKey) {
        return decryptSm2ToString(hexStr, privateKey, HexUtil::decode);
    }

    /**
     * SM2解密
     *
     * @param base64Str  待解密base64字符串
     * @param privateKey 密钥
     * @return 解密后的数据
     */
    public static byte[] decryptSm2FromBase64(String base64Str, byte[] privateKey) {
        return decryptSm2(base64Str, privateKey, Base64Util::decode);
    }

    /**
     * SM2解密，转为字符串
     *
     * @param base64Str  待解密base64字符串
     * @param privateKey 密钥
     * @return 解密后的字符串
     */
    public static String decryptSm2FromBase64ToString(String base64Str, byte[] privateKey) {
        return decryptSm2ToString(base64Str, privateKey, Base64Util::decode);
    }

    /**
     * 加密
     *
     * @param cipherAlgorithm 算法模式
     * @param data            待加密数据
     * @param secretKey       密钥
     * @param iv              初始化向量
     * @return 加密后的数据
     */
    @SuppressWarnings("unchecked")
    public static byte[] encrypt(CipherAlgorithm cipherAlgorithm, byte[] data, String secretKey, String iv) {
        Encryptor<SymmetricEncryptorOptions> encryptor = (Encryptor<SymmetricEncryptorOptions>) getEncryptor(cipherAlgorithm);
        SymmetricEncryptorOptions options = new SymmetricEncryptorOptions(cipherAlgorithm, secretKey, iv);
        return encryptor.encrypt(data, options);
    }

    /**
     * 加密
     *
     * @param cipherAlgorithm 算法模式
     * @param str             待加密字符串
     * @param secretKey       密钥
     * @param iv              初始化向量
     * @return 加密后的数据
     */
    public static byte[] encrypt(CipherAlgorithm cipherAlgorithm, String str, String secretKey, String iv) {
        return encrypt(cipherAlgorithm, StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * 加密
     *
     * @param cipherAlgorithm 算法模式
     * @param data            待加密数据
     * @param publicKey       公钥
     * @return 加密后的数据
     */
    @SuppressWarnings("unchecked")
    public static byte[] encrypt(CipherAlgorithm cipherAlgorithm, byte[] data, byte[] publicKey) {
        Encryptor<AsymmetricEncryptorOptions> encryptor = (Encryptor<AsymmetricEncryptorOptions>) getEncryptor(cipherAlgorithm);
        AsymmetricEncryptorOptions options = new AsymmetricEncryptorOptions(cipherAlgorithm, publicKey, null);
        return encryptor.encrypt(data, options);
    }

    /**
     * 加密
     *
     * @param cipherAlgorithm 算法模式
     * @param str             待加密字符串
     * @param publicKey       公钥
     * @return 加密后的数据
     */
    public static byte[] encrypt(CipherAlgorithm cipherAlgorithm, String str, byte[] publicKey) {
        return encrypt(cipherAlgorithm, StringUtil.getBytes(str), publicKey);
    }

    /**
     * 解密
     *
     * @param cipherAlgorithm 算法模式
     * @param data            待解密数据
     * @param secretKey       密钥
     * @param iv              初始化向量
     * @return 加密后的数据
     */
    @SuppressWarnings("unchecked")
    public static byte[] decrypt(CipherAlgorithm cipherAlgorithm, byte[] data, String secretKey, String iv) {
        Encryptor<SymmetricEncryptorOptions> encryptor = (Encryptor<SymmetricEncryptorOptions>) getEncryptor(cipherAlgorithm);
        SymmetricEncryptorOptions options = new SymmetricEncryptorOptions(cipherAlgorithm, secretKey, iv);
        return encryptor.decrypt(data, options);
    }

    /**
     * 解密
     *
     * @param cipherAlgorithm 算法模式
     * @param str             待解密字符串
     * @param secretKey       密钥
     * @param iv              初始化向量
     * @return 加密后的数据
     */
    public static byte[] decrypt(CipherAlgorithm cipherAlgorithm, String str, String secretKey, String iv) {
        return decrypt(cipherAlgorithm, StringUtil.getBytes(str), secretKey, iv);
    }

    /**
     * 解密
     *
     * @param cipherAlgorithm 算法模式
     * @param data            待解密数据
     * @param privateKey      私钥
     * @return 加密后的数据
     */
    @SuppressWarnings("unchecked")
    public static byte[] decrypt(CipherAlgorithm cipherAlgorithm, byte[] data, byte[] privateKey) {
        Encryptor<AsymmetricEncryptorOptions> encryptor = (Encryptor<AsymmetricEncryptorOptions>) getEncryptor(cipherAlgorithm);
        AsymmetricEncryptorOptions options = new AsymmetricEncryptorOptions(cipherAlgorithm, null, privateKey);
        return encryptor.decrypt(data, options);
    }

    /**
     * 解密
     *
     * @param cipherAlgorithm 算法模式
     * @param str             待解密字符串
     * @param privateKey      私钥
     * @return 加密后的数据
     */

    public static byte[] decrypt(CipherAlgorithm cipherAlgorithm, String str, byte[] privateKey) {
        return decrypt(cipherAlgorithm, StringUtil.getBytes(str), privateKey);
    }

    /**
     * 获取加密器
     *
     * @param cipherAlgorithm 加密算法
     * @return 加密器
     */
    private static Encryptor<?> getEncryptor(CipherAlgorithm cipherAlgorithm) {
        Assert.notNull(cipherAlgorithm, "Cipher algorithm must not be null");
        Encryptor<?> encryptor = EncryptorFactory.getEncryptor(cipherAlgorithm);
        if (encryptor == null) {
            throw new IllegalArgumentException("Unsupported cipher algorithm \"" + cipherAlgorithm.getFullAlgorithm() + "\"");
        }
        return encryptor;
    }

    /**
     * 检查转换函数
     *
     * @param converter 转换函数
     */
    private static void checkConverter(Function<?, ?> converter) {
        Assert.notNull(converter, "Converter function must not be null");
    }

}
